#include <trax.hpp>
#include "atMaterial.h"
#include "Ray.h"
#include "Color.h"
#include "RayTracer.h"
#include "Vector3.h"
#include "RayTracer.h"

namespace AtomTrace
{

	//using namespace Material;
	bool Material::BouncePhoton(Ray & outRay, Color & c, HitRecord & hit, const Scene & sce, const Color& lInten)
	{
		// Assuming every material only has one property, such as only diffuse or only reflection
		int matAddr = sce.startMatAddr + hit.matID*25;
		hit.transIndex = loadf(matAddr, 16);
        GetNewDir(hit.matIllum, hit, outRay._dir, true);
		outRay = RayTracer::CastRay(hit.P, outRay._dir);
		// TODO: more photon code
		if(hit.matIllum != 3 && hit.matIllum != 6)
		{
			Color diff;
			diff.LoadFromGM(matAddr + 4);
            /***
            if (diff[0] > 1.0f || diff[1] > 1.0f || diff[2] > 1.0f) {
                //printf("bounce diff [%f, %f, %f]\n", diff[0], diff[1], diff[2]);
                //c = lInten;
            }
            else
            // **/
            {
                diff.Clamp(0.0f, 1.0f); // light source material should clamp to [0, 1] because photon already carry this information
                c *= diff;
            }
            //diff.Set(1.0f, 0.0f, 0.0f);
			
		}
        
		return true;
	}

	bool Material::GetNewDir(int illumID, HitRecord & hit, Vector3 & oDir, bool isPhoton)
	{
		/**
		0. Color on and Ambient off
		1. Color on and Ambient on
		2. Highlight on
		3. Reflection on and Ray trace on
		4. Transparency: Glass on, Reflection: Ray trace on
		5. Reflection: Fresnel on and Ray trace on
		6. Transparency: Refraction on, Reflection: Fresnel off and Ray trace on
		7. Transparency: Refraction on, Reflection: Fresnel on and Ray trace on
		8. Reflection on and Ray trace off
		9. Transparency: Glass on, Reflection: Ray trace off
		10. Casts shadows onto invisible surfaces
		// **/
		switch(illumID)
		{
		case 3:
			oDir = ReflectionDir(hit.GetTriangleNormal(), hit.incDir * -1.0f);
			break; // reflection
		case 6:
			oDir = RefractionDir(hit.GetTriangleNormal(), hit.incDir * -1.0f, hit.transIndex);
			break; // refraction
		default:
			if(isPhoton)
				oDir = RandomHemiDirection(hit.GetTriangleNormal());
                //oDir = hit.N;
			else
				oDir.SetZero();
			break;
		}
		return true;
	}

}
